/*
 *  Copyright © 2014 CIB Co.Ltd
 *  * All right reserved
 *  * Auther:jin xingwang
 *
 */

package com.wsd.interceptor;

import com.alibaba.fastjson.JSON;
import com.jwts.common.JwtClaims;
import com.jwts.common.Jwts;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;

/**
 * 模块/功能
 * @author 靳兴旺
 * @version 1.0.0 2020-7-16
 * 自定义Web拦截器
 */
@Component
public class WebInterceptor implements HandlerInterceptor, ApplicationListener<ContextRefreshedEvent> {

    @Value("${jwt.login-logout.requestUrl}")
    private String loginLogoutUrl;

    /** 允许登陆和未登陆状态下都能请求的Url列表 */
    private Set<String> loginOutSet;

    /**
     * Spring容器创建完后执行
     * @param contextRefreshedEvent 事件
     */
    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        loginOutSet = new HashSet<>(64);
        String[] urls = loginLogoutUrl.replaceAll(" ", "").split(",");
        Collections.addAll(loginOutSet, urls);
    }

    /**
     * 预处理，再controller处理前调用
     * @param httpServletRequest 请求
     * @param httpServletResponse 响应
     * @param o 对象
     * @return 是否通过
     * @throws Exception 异常
     */
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        String authorization = httpServletRequest.getHeader("Authorization");
        //bearer token的前缀
        final String preToken = "Bearer ";
        if (authorization == null || !authorization.startsWith(preToken)) {
            //判断是否可以未登录也能请求Url
            if (loginOutSet.contains(httpServletRequest.getRequestURI())){
                return true;
            }
            return noAccess403(httpServletResponse);
        } else {
            try {
                String token = authorization.substring(7).replaceAll(" ", "");

                /* 验证token的完整性和有效性 */
                if (!StringUtils.isEmpty(token) && Jwts.safetyVerification(token)) {
                    JwtClaims jwtClaims = JSON.parseObject(Base64.decodeBase64(token.split("\\.")[1]), JwtClaims.class);
                    httpServletResponse.setHeader("Authorization", httpServletRequest.getHeader("Authorization"));
                    httpServletRequest.setAttribute("claims", jwtClaims);
                    return true;
                }
            } catch (Exception e){
                e.getMessage();
                return noAccess403(httpServletResponse);
            }
        }
        return noAccess403(httpServletResponse);
    }

    /**
     * 未登录状态下请求了接口或登陆状态失效时请求需要登陆状态才能请求的URL
     * @param httpServletResponse 响应
     * @return 是否通过
     * @throws Exception 未知异常
     */
    public boolean noAccess403(HttpServletResponse httpServletResponse) throws Exception{
        httpServletResponse.sendError(403);
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {

    }
}
